package edu.uiuc.ncsa.kmltordf;

import edu.uiuc.ncsa.commons.NCSAKMLUtilityException;
import edu.uiuc.ncsa.commons.util.Util;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * @author : Sachith Dhanushka (sachith.dhanushka@gmail.com)
 * @date : @date : Aug 5, 2008 - 12:10:58 AM
 */
public class Converter {

    public void convert(InputStream input, OutputStream output, String parentURL) throws NCSAKMLUtilityException {

        try {
            Document sourceDocument = Util.parseXmlFile(input);
            Element sourceDocElement = sourceDocument.getDocumentElement();

            DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            Document outputDocument = builder.newDocument();

            // define root level namespaces
            Element outputDocumentElement = outputDocument.createElement("rdf:RDF");
            outputDocument.appendChild(outputDocumentElement);

            outputDocumentElement.setAttribute("xmlns:rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
            outputDocumentElement.setAttribute("xmlns:kml", "http://www.opengis.net/kml/2.2");
            outputDocumentElement.setAttribute("xmlns:gml", "http://www.opengis.net/gml");
            outputDocumentElement.setAttribute("xmlns:ds", "http://cet.ncsa.uiuc.edu/2008/2/20/Data.owl#");
            outputDocumentElement.setAttribute("xmlns:time", "http://www.w3.org/2006/time#");
//            outputDocumentElement.setAttribute("xmlns:dcterms", "http://purl.org/dc/terms/");

            // get all ground overlays
            NodeList groundOverlayNodes = evaluateXPath(sourceDocElement, "//GroundOverlay");
            if (groundOverlayNodes != null) {

                // get ready for current date
                Format formatter = new SimpleDateFormat("ddMMyyyy-HHmmss");
                String dateString = formatter.format(new Date());

                for (int index = 0; index < groundOverlayNodes.getLength(); index++) {
                    Element node = (Element) groundOverlayNodes.item(index);

                    // get begin part
                    NodeList beginElements = evaluateXPath(node, "TimeSpan/begin");

                    // get end time
                    NodeList endElements = evaluateXPath(node, "TimeSpan/end");

                    // get north, south, east and west
                    NodeList northElements = evaluateXPath(node, "LatLonBox/north");
                    NodeList southElements = evaluateXPath(node, "LatLonBox/south");
                    NodeList eastElements = evaluateXPath(node, "LatLonBox/east");
                    NodeList westElements = evaluateXPath(node, "LatLonBox/west");

                    // now add these to output

                    //<ds:DataStreamToken rdf:about="http://www.srh.noaa.gov/data/radar/poly.kml/accessed#20080801 0615 UTC">
                    Element dataStreamToken = outputDocument.createElement("ds:DataStreamToken");
                    dataStreamToken.setAttribute("rdf:about", parentURL + "/accessed#" + dateString);
                    outputDocumentElement.appendChild(dataStreamToken);

                    //    <ds:hasTimeOfOccurrence>
                    Element hasTimeOfOccurrence = outputDocument.createElement("ds:hasTimeOfOccurrence");
                    dataStreamToken.appendChild(hasTimeOfOccurrence);

                    //      <time:Instant>
                    Element instant = outputDocument.createElement("time:Instant");
                    hasTimeOfOccurrence.appendChild(instant);

                    //        <time:inXSDDateTime rdf:datatype="http://www.w3.org/2001/XMLSchema#DateTime">20080801 0615 UTC</time:inXSDDateTime>
                    Element inXSDDateTime = outputDocument.createElement("time:inXSDDateTime");
                    inXSDDateTime.setAttribute("rdf:datatype", "http://www.w3.org/2001/XMLSchema#DateTime");
                    inXSDDateTime.setTextContent(dateString);
                    instant.appendChild(inXSDDateTime);

                    //      </time:Instant>
                    //    </ds:hasTimeOfOccurrence>

                    //      <kml:GroundOverlay rdf:about="http://www.srh.noaa.gov/data/radar/poly.kml/vtec20080801 0615 UTC">
                    Element groundOverlay = outputDocument.createElement("kml:GroundOverlay");
                    groundOverlay.setAttribute("rdf:about", parentURL + "/accessed#" + dateString);
                    dataStreamToken.appendChild(groundOverlay);

                    //        <dcterms:TimeSpan>
                    Element timeSpan = outputDocument.createElement("kml:TimeSpan");
                    groundOverlay.appendChild(timeSpan);

                    //          <time:Interval>
                    Element interval = outputDocument.createElement("time:Interval");
                    timeSpan.appendChild(interval);

                    //            <time:hasBeginning>
                    Element hasBeginning = outputDocument.createElement("time:hasBeginning");
                    interval.appendChild(hasBeginning);

                    //              <time:Instant>
                    Element timeInstant = outputDocument.createElement("time:Instant");
                    hasBeginning.appendChild(timeInstant);

                    //                <time:inXSDDateTime rdf:datatype="http://www.w3.org/2001/XMLSchema#DateTime">2008-08-01T06:10:00Z</time:inXSDDateTime>
                    inXSDDateTime = outputDocument.createElement("time:inXSDDateTime");
                    inXSDDateTime.setAttribute("rdf:datatype", "http://www.w3.org/2001/XMLSchema#DateTime");
                    timeInstant.appendChild(inXSDDateTime);
                    inXSDDateTime.setTextContent(((Element) beginElements.item(0)).getTextContent());

                    //              </time:Instant>
                    //            </time:hasBeginning>

                    //            <time:hasEnd>
                    Element hasEnd = outputDocument.createElement("time:hasEnd");
                    interval.appendChild(hasEnd);

                    //              <time:Instant>
                    timeInstant = outputDocument.createElement("time:Instant");
                    hasEnd.appendChild(timeInstant);

                    //                <time:inXSDDateTime rdf:datatype="http://www.w3.org/2001/XMLSchema#DateTime">2008-08-01T06:35:00Z</time:inXSDDateTime>
                    inXSDDateTime = outputDocument.createElement("time:inXSDDateTime");
                    inXSDDateTime.setAttribute("rdf:datatype", "http://www.w3.org/2001/XMLSchema#DateTime");
                    timeInstant.appendChild(inXSDDateTime);
                    inXSDDateTime.setTextContent(((Element) endElements.item(0)).getTextContent());

                    //              </time:Instant>
                    //            </time:hasEnd>
                    //          </time:Interval>
                    //        </dcterms:TimeSpan>

                    //        <dcterms:spatial>
                    Element spatial = outputDocument.createElement("kml:spatial");
                    groundOverlay.appendChild(spatial);

                    //          <gml:Box>
                    Element box = outputDocument.createElement("gml:Box");
                    spatial.appendChild(box);

                    //            <gml:coordinates>
                    Element coordinates = outputDocument.createElement("gml:coordinates");
                    box.appendChild(coordinates);
                    coordinates.setTextContent(((Element) northElements.item(0)).getTextContent() + "," + ((Element) westElements.item(0)).getTextContent() + "," +
                            ((Element) southElements.item(0)).getTextContent() + "," + ((Element) eastElements.item(0)).getTextContent());
                }
            }


            serialize(outputDocument, output);

        } catch (ParserConfigurationException e) {
            throw new NCSAKMLUtilityException(e);
        } catch (XPathExpressionException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }


    }

    public NodeList evaluateXPath(Node node, String xpathString) throws XPathExpressionException {
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = xpath.compile(xpathString);
        return (NodeList) expr.evaluate(node, XPathConstants.NODESET);
    }

    public void serialize(Document document, OutputStream out) {
        try {
            OutputFormat format = new OutputFormat(document);
            XMLSerializer output = new XMLSerializer(out, format);
            format.setIndenting(true);

            output.serialize(document);
        }
        catch (IOException e) {
            System.err.println(e);
        }
    }

    public static void main(String[] args) {
        try {
            Converter converter = new Converter();
            String urlString = "http://code.google.com/apis/kml/documentation/TimeSpan_example.kml";
            URL url = new URL(urlString);

            converter.convert(url.openStream(), null, urlString);

            url = new URL("http://www.guiweather.com/kml/radar/radarAnimator.php");
            converter.convert(url.openStream(), null, "http://www.guiweather.com/kml/radar/radarAnimator.php");
        } catch (NCSAKMLUtilityException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }

}
